<template>
  <el-select
    popper-class="virtual-list"
    clearable
    :multiple="multiple"
    v-model="selectValue"
    v-loadmore="loadMore"
    default-first-option
    :collapse-tags="multiple && collapse_tags"
    :max-collapse-tags="max_collapse_tags"
    :filterable="filterable"
    :filter-method="handleFilter"
    :disabled="disabled"
    ref="virtualList"
    @visible-change="handleVisible"
    @change="handleChange"
    @blur="handleSelectBlur"
  >
    <el-option
      v-for="item in visibleList"
      :key="obj ? (item as SelectOptionsType).id : item"
      :value="obj ? (item as SelectOptionsType).id : item"
      :label="obj ? (item as SelectOptionsType).name : item"
    ></el-option>
  </el-select>
</template>

<script setup lang="ts">
import type { SelectInstance } from 'element-plus';
import { onMounted, ref, useTemplateRef, watch, type PropType } from 'vue';

export interface SelectOptionsType {
  id: string;
  name: string;
}

const props = defineProps({
  list: {
    type: Array as PropType<SelectOptionsType[] | string[]>,
    required: true,
    default: () => [],
  },
  value: {
    type: [Array, String] as PropType<string[] | string>,
    default: '',
  },
  multiple: {
    type: Boolean,
    default: false,
  },
  obj: {
    type: Boolean,
    default: false,
  },
  collapse_tags: {
    type: Boolean,
    default: true,
  },
  filterable: {
    type: Boolean,
    default: true,
  },
  disabled: {
    type: Boolean,
    default: false,
  },
  max_collapse_tags: {
    type: Number,
    default: 2,
  },
});

const emit = defineEmits<{
  selectValue: [string | string[]];
}>();

const visibleList = ref<SelectOptionsType[] | string[]>([]);
const selectValue = ref(props.value);
const ulEl = ref<HTMLElement | null>(null);
const visibleView = ref<HTMLElement | null>(null);
const scrollView = ref<HTMLElement | null>(null);
const scrollTop = ref<number>(0);
const listAll = ref<SelectOptionsType[] | string[]>([]);

const virtualListRef = useTemplateRef<SelectInstance>('virtualList');

onMounted(() => {
  if (virtualListRef.value) {
    const el = virtualListRef.value.$el;
    ulEl.value = el.querySelector(
      '.virtual-list .el-select-dropdown__wrap.el-scrollbar__wrap .el-scrollbar__view.el-select-dropdown__list',
    );
    visibleView.value = el.querySelector('.virtual-list .visible-list');
    scrollView.value = el.querySelector(
      '.virtual-list .el-select-dropdown__wrap.el-scrollbar__wrap',
    );
    listAll.value = [...props.list] as SelectOptionsType[] | string[];
    const height = listAll.value.length * 34;
    visibleList.value = listAll.value.slice(0, 8);
    if (visibleView.value) visibleView.value.style.height = `${height}px`;
    if (ulEl.value) ulEl.value.style.transform = 'translateY(0px)';
  }
});

// 加载更多方法
const loadMore = (firstIndex: number, secondIndex: number, scrollTopVal: number) => {
  visibleList.value = listAll.value.slice(firstIndex, secondIndex);
  if (ulEl.value) ulEl.value.style.transform = `translateY(${firstIndex * 34}px)`;
  scrollTop.value = scrollTopVal;
};

// 处理下拉框显示/隐藏
const handleVisible = (value: boolean) => {
  if (value) {
    if (ulEl.value) ulEl.value.style.transform = 'translateY(0px)';
    visibleList.value = listAll.value.slice(0, 8);
  }
  listAll.value = [...props.list] as SelectOptionsType[] | string[];
  const height = listAll.value.length * 34;
  visibleList.value = listAll.value.slice(0, 8);
  if (visibleView.value) visibleView.value.style.height = `${height}px`;
  if (ulEl.value) ulEl.value.style.transform = 'translateY(0px)';
};

// 自定义搜索
const handleFilter = (value: string) => {
  listAll.value = props.list.filter((item: SelectOptionsType | string) => {
    if (props.obj) {
      return (item as SelectOptionsType).name.indexOf(value) >= 0;
    } else {
      return (item as string).indexOf(value) >= 0;
    }
  }) as SelectOptionsType[] | string[];
  const height = listAll.value.length > 6 ? listAll.value.length * 34 : 7 * 34;
  visibleList.value = listAll.value.slice(0, 8);
  if (visibleView.value) visibleView.value.style.height = `${height}px`;
  if (ulEl.value) ulEl.value.style.transform = 'translateY(0px)';
};

const handleChange = (value: string | string[]) => {
  emit('selectValue', value);
};

const handleSelectBlur = (e: FocusEvent) => {
  console.log('blur', e);
};

watch(
  () => props.list,
  () => {
    listAll.value = [...props.list] as SelectOptionsType[] | string[];
    const height = listAll.value.length * 34;
    visibleList.value = listAll.value.slice(0, 8);
    if (visibleView.value) visibleView.value.style.height = `${height}px`;
    if (ulEl.value) ulEl.value.style.transform = 'translateY(0px)';
  },
);

watch(
  () => props.value,
  (val) => {
    selectValue.value = val;
  },
);
</script>

<style scoped lang="scss"></style>
